package top.lishuoboy.shiro;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import top.lishuoboy.shiro.realm.CustomizeMd5Realm;

import java.util.Arrays;

/**
 * 认证 Authentication [ɔːˌθentɪˈkeɪʃn]
 * 授权 Authorization  [ˌɔːθərəˈzeɪʃn]
 */
@Slf4j
public class TestShiro {
    public static void main(String[] args) {

        // 一、通过ini领域创建 SecurityManager
        //1.创建安全管理器对象
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        //2.给安全管理器设置realm
//        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
//        securityManager.setRealm(new CustomizeRealm());
        //设置realm使用hash凭证匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //使用算法
        credentialsMatcher.setHashAlgorithmName("MD5");
        //散列次数
        credentialsMatcher.setHashIterations(1024);
        //注入realm
        CustomizeMd5Realm customizeMd5Realm = new CustomizeMd5Realm();
        customizeMd5Realm.setCredentialsMatcher(credentialsMatcher);
        securityManager.setRealm(customizeMd5Realm);
        //3.SecurityUtils 给全局安全工具类设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);

        // 二、验证当前用户
        //4.关键对象 subject 主体
        Subject subject = SecurityUtils.getSubject();
        //5.创建令牌
        UsernamePasswordToken token;
        token = new UsernamePasswordToken("zhangsan", "111111");  // 认证成功
//        token = new UsernamePasswordToken("zhangsan11", "111111"); // 认证失败: 用户名不存在~
//        token = new UsernamePasswordToken("zhangsan", "11111122"); // 认证失败: 密码错误~
        try {
            log.debug("认证状态, subject.isAuthenticated()=={}", subject.isAuthenticated());
            subject.login(token);//用户认证
            log.debug("认证状态, subject.isAuthenticated()=={}", subject.isAuthenticated());
        } catch (UnknownAccountException e) {
            log.warn("认证失败: 用户名不存在~", e);
        } catch (IncorrectCredentialsException e) {
            log.warn("认证失败: 密码错误~", e);
        } catch (AuthenticationException e) {
            // AuthenticationException是很多认证异常的父类，包括:
            // UnknownAccountException(用户名不存在)、
            // IncorrectCredentialsException(密码错误)、
            // DisabledAccountException（帐号被禁用）、
            // LockedAccountException（帐号被锁定）等等
            // ExcessiveAttemptsException（登录失败次数过多）
            // ExpiredCredentialsException（凭证过期）等
            log.warn("认证失败", e);
        }


        //授权
        if (subject.isAuthenticated()) { // 已经认证通过
            // 一、角色
            // 拥有一个角色 hasRole()，调用一次doGetAuthenticationInfo()
            log.info("hasRole()=={}", subject.hasRole("admin")); // true
            log.info("hasRole()=={}", subject.hasRole("other")); // false

            // 同时拥有n个角色 hasAllRoles()，调用n次doGetAuthenticationInfo()
            log.info("hasAllRoles()=={}", subject.hasAllRoles(Arrays.asList("admin", "user")));  // true
            log.info("hasAllRoles()=={}", subject.hasAllRoles(Arrays.asList("admin", "other"))); // false

            // 分别拥有n个角色hasRoles()结果列表，返回每个角色的拥有结果，调用n次doGetAuthenticationInfo()
            boolean[] isHasRoleArr = subject.hasRoles(Arrays.asList("admin", "user", "other"));
            log.info("isHasRoleArr=={}", isHasRoleArr);  // isHasRoleArr==[true, true, false]

            // 二、权限。基于权限字符串的访问控制  资源标识符:操作:资源类型
            // 拥有一个权限 isPermitted()，调用一次doGetAuthenticationInfo()
            log.info("isPermitted()=={}", subject.isPermitted("user:*:01"));        // true
            log.info("isPermitted()=={}", subject.isPermitted("user:insert:01"));   // true
            log.info("isPermitted()=={}", subject.isPermitted("user:remove"));      // false  相当于 user:remove:*

            log.info("isPermitted()=={}", subject.isPermitted("product:add:*"));    // true
            log.info("isPermitted()=={}", subject.isPermitted("product:add"));      // true  相当于 product:add:*
            log.info("isPermitted()=={}", subject.isPermitted("product:add:02"));   // true
            log.info("isPermitted()=={}", subject.isPermitted("product:remove"));   // false 相当于 product:remove:*

            // 同时拥有n个权限 isPermittedAll()，调用n次doGetAuthenticationInfo()
            boolean isPermittedAll = subject.isPermittedAll("user:*:01", "user:insert:01");
            log.info("isPermittedAll=={}", isPermittedAll);     // isPermittedAll==true

            // 拥有n个角色hasRoles()结果列表，返回每个角色的拥有结果，调用n次doGetAuthenticationInfo()
            boolean[] isPermittedArr = subject.isPermitted("user:*:01", "user:insert:01", "user:remove");
            log.info("isPermittedArr=={}", isPermittedArr);     // isPermittedArr==[true, true, false]


        }

    }
}

